package allrobots.TraceAndAvoid;

import allrobots.DispensingMachine.DMAndRobotSocket;
import allrobots.DispensingMachine.WaitPosition;
import allrobots.Robot.RobotMessage;
import allrobots.Robot.RobotMessageMap;
import allrobots.Robot.RobotsSocketMap;
import allrobots.pojo.BroadcastMessage;
import allrobots.sendMessages.ChangeStatus.ChangeRobot;
import t10086.Data.Map.GridType;
import t10086.Data.Map.T10086Map;
import t10086.Data.Map.TextCoordinate;
import t10086.Data.Robot.RobotInfo;
import t10086.Data.Robot.RobotStatus;
import t10086.Data.Broadcast;
import t10086.Model.Messages.Message;
import t10086.Model.Messages.MessageType;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.CyclicBarrier;

//1.MOVING状态下寻路避障
//2.QUEUING状态下自动排队
public class Move {
    private Socket socket;
    private int robotId;
    private int windowId;
    private List<Integer> crashRobotId = new ArrayList<>();//会撞的机器人列表，内容是机器人ID
    private Map<String, Integer> crashPriority = new HashMap<>();//碰撞优先级，<前进方向,优先级数>

    public Move(Socket socket, int robotId) {
        this.socket = socket;
        this.robotId = robotId;
        crashPriority.put("WEST", 4);
        crashPriority.put("SOUTH", 3);
        crashPriority.put("NORTH", 2);
        crashPriority.put("EAST", 1);
    }

    //排队时往前走一步
    public void moveAStep(String Direction) {
        RobotMessage robot = RobotMessageMap.robotMap.get(robotId);
        TextCoordinate cur = robot.getPosition();
        switch (Direction) {
            case "NORTH" -> cur.x--;
            case "SOUTH" -> cur.x++;
            case "EAST" -> cur.y++;
            case "WEST" -> cur.y--;
            default -> throw new IllegalArgumentException("Invalid direction: " + Direction);
        }
        robot.setPosition(cur);
        RobotMessageMap.setRobotMessage(robotId, robot);
    }

    public TextCoordinate calTerminationPos(TextCoordinate windowPos, String Direction, int queueLength) {
        switch (Direction) {
            case "NORTH":
                windowPos.x += queueLength;
                break;
            case "SOUTH":
                windowPos.x -= queueLength;
                break;
            case "EAST":
                windowPos.y -= queueLength;
            case "WEST":
                windowPos.y += queueLength;
        }
        return windowPos;
    }

    public void decideTermination() {
        List<Integer> costList = new ArrayList<>();
        Broadcast broadcastInfo = BroadcastMessage.broadcastMessage;
        T10086Map map = broadcastInfo.getMap();
        for (int i = 0; i < broadcastInfo.getWindowMap().size(); i++) {
            RobotMessage robot = RobotMessageMap.robotMap.get(robotId);
            robot.setTermination(calTerminationPos(broadcastInfo.getWindowMap().get(i), "WEST", 5));
            Route route = new Route(robot, map);
            int sumCost = route.getFinalRoute().size() + broadcastInfo.getQueuingQueues().get(i).size() * 5;
            costList.add(sumCost);
        }
        int min_index = 0;
        for (int i = 0; i < costList.size(); i++) {
            if (costList.get(i) < costList.get(min_index)) {
                min_index = i;
            }
        }
        windowId = min_index;
        RobotMessage robot1 = RobotMessageMap.robotMap.get(robotId);
        robot1.setTermination(broadcastInfo.getWindowMap().get(min_index));
        robot1.setWindow(windowId);
        RobotMessageMap.setRobotMessage(robotId, robot1);
        TextCoordinate waitPosition = new TextCoordinate(broadcastInfo.getWindowMap().get(min_index));
        WaitPosition.waitposition.put(robotId, waitPosition);
    }

    private String getDirection(RobotMessage robot) {
        if (robot == null) {
            return "EAST";
        } else {
            TextCoordinate cur = new TextCoordinate(robot.getPosition());
            TextCoordinate next = new TextCoordinate(robot.getNext());
            if (next.x < cur.x && next.y == cur.y) return "NORTH";
            else if (next.x > cur.x && next.y == cur.y) return "SOUTH";
            else if (next.x == cur.x && next.y < cur.y) return "WEST";
            else if (next.x == cur.x && next.y > cur.y) return "EAST";
            else return "SOUTH";
        }
    }

    public boolean willCrash(TextCoordinate nextPos) {
        Broadcast broadcastInfo = BroadcastMessage.broadcastMessage;
        for (RobotInfo robotInfo : broadcastInfo.getRobotInfoMap().values()) {//遍历robot信息表
            if (robotInfo.getNext().x == nextPos.x && robotInfo.getNext().y == nextPos.y) {
                crashRobotId.add(Integer.parseInt(robotInfo.getSerialNumber()));
            }
        }
        //System.out.println("此时的会撞列表是" + crashRobotId);
        return crashRobotId.size() > 1;
    }

    public int avoid() throws IOException {
        Broadcast broadcastInfo = BroadcastMessage.broadcastMessage;
        T10086Map map = broadcastInfo.getMap();
        RobotMessage robot = RobotMessageMap.robotMap.get(robotId);
        if (broadcastInfo.getMovingNumber() >= robot.getSelfMovingNumber()) {
            //若到达目的地，更新机器人状态
            RobotMessage robot4 = RobotMessageMap.robotMap.get(robotId);
            long movingNumber = broadcastInfo.getMovingNumber() + 1;
            robot4.setSelfMovingNumber(movingNumber);
            RobotMessageMap.setRobotMessage(robotId, robot4);
            TextCoordinate waitPosition = new TextCoordinate(BroadcastMessage.broadcastMessage.getWindowMap().get(robot4.getWindow()).getX(), BroadcastMessage.broadcastMessage.getWindowMap().get(robot4.getWindow()).getY() + 5);
            if ((robot4.getPosition().x == robot4.getTermination().x && robot4.getPosition().y == robot4.getTermination().y)) {
                if (DMAndRobotSocket.robotsSocketMap.containsKey(robot4.getSerialNum())) {
                    //到发药机
                    Message responseDM = new Message(MessageType.RESPONSE, "react");
                    ObjectOutputStream out = DMAndRobotSocket.robotsSocketMap.get(robot4.getSerialNum()).getOos();
                    out.writeObject(responseDM);
                    out.flush();
                    //System.out.println("告诉发药机我到了");
                } else if (robot4.getTermination().equals(robot4.getBornPosition())) {
                    //回家状态
                    Message statusChange = new Message(MessageType.STATUS_EXCHANGE, new ChangeRobot(robot4.getSerialNum(), robot4.getRobotStatus(), RobotStatus.FREE, null));
                    statusChange.setSender((InetSocketAddress) RobotsSocketMap.robotsSocketMap.get(robotId).getSocket().getLocalSocketAddress());
                    statusChange.setReceiver((InetSocketAddress) RobotsSocketMap.robotsSocketMap.get(robotId).getSocket().getRemoteSocketAddress());
                    RobotsSocketMap.robotsSocketMap.get(robotId).getOos().writeObject(statusChange);
                    RobotsSocketMap.robotsSocketMap.get(robotId).getOos().flush();
                    robot4.setRobotStatus(RobotStatus.FREE);
                    RobotMessageMap.robotMap.put(robotId, robot4);
                    //System.out.println("回家了");
                    return 1;
                } else if (robot4.getTermination().equals(waitPosition)) {
                    //到排队队列
                    Message statusChange = new Message(MessageType.STATUS_EXCHANGE, new ChangeRobot(robot4.getSerialNum(), robot4.getRobotStatus(), RobotStatus.QUEUING, robot4.getWindow()));
                    statusChange.setSender((InetSocketAddress) RobotsSocketMap.robotsSocketMap.get(robotId).getSocket().getLocalSocketAddress());
                    statusChange.setReceiver((InetSocketAddress) RobotsSocketMap.robotsSocketMap.get(robotId).getSocket().getRemoteSocketAddress());
                    RobotsSocketMap.robotsSocketMap.get(robotId).getOos().writeObject(statusChange);
                    RobotsSocketMap.robotsSocketMap.get(robotId).getOos().flush();
                    robot4.setRobotStatus(RobotStatus.QUEUING);
                    RobotMessageMap.robotMap.put(robotId, robot4);
                    //设置窗口地址
                    robot4.setTermination(BroadcastMessage.broadcastMessage.getWindowMap().get(robot4.getWindow()));
                    RobotMessageMap.robotMap.put(robotId, robot4);
                }
//                System.out.println("到达终点了");
            } else {//没到达目的地，寻路并传出下一步想走的地方
                //判断是否会撞
                if (broadcastInfo.getMap().getGrid(robot4.getNext()).getGridType() == GridType.ROBOT) {
                    RobotMessage robot5 = RobotMessageMap.robotMap.get(robotId);
                    Route route = new Route(robot5, map);
                    TextCoordinate nextPos = route.getNextStep();
                    robot5.setNext(nextPos);
                    RobotMessageMap.setRobotMessage(robotId, robot5);
                    System.out.println("防追尾");
                } else if (willCrash(robot.getNext())) {
//                    System.out.println("-----------------------------进入碰撞判断-----------------------------------");
//                    System.out.println(robotId + "现在在" + robot.getPosition());
//                    System.out.println(robotId + "下一个位置" + robot.getNext());
//                    System.out.println(robotId + "想往" + getDirection(robot));
                    //避撞逻辑：优先级WEST>SOUTH>NORTH>EAST
                    System.out.println("会撞时的列表为" + crashRobotId);
                    int maxPriority = 0;//会撞的列表里优先级的最高数
                    for (int i : crashRobotId) {//遍历会撞的列表，让maxPriority和表中每个机器人的优先级数对比，找到表中最大的优先级数
                        RobotMessage robot6 = RobotMessageMap.robotMap.get(i);
                        System.out.println(i + "的优先级是" + crashPriority.get(getDirection(robot6)));
                        if (crashPriority.get(getDirection(robot6)) >= maxPriority) {
                            maxPriority = crashPriority.get(getDirection(robot6));
                        }
                    }
                    //看优先级最高的是不是自己
//                    System.out.println("此时最高的优先级是" + maxPriority);
                    RobotMessage robot1 = RobotMessageMap.robotMap.get(robotId);
//                    System.out.println(robotId + "的优先级是" + crashPriority.get(getDirection(robot1)));
                    if (crashPriority.get(getDirection(robot1)) == maxPriority) {
                        //走一步
//                        System.out.println(robotId + "的优先级最高,想往" + getDirection(RobotMessageMap.robotMap.get(robotId)));
                        robot1.setPosition(robot1.getNext());
                        RobotMessageMap.setRobotMessage(robotId, robot1);
                    }
                } else {
                    //走一步
                    RobotMessage robot3 = RobotMessageMap.robotMap.get(robotId);
                    robot3.setPosition(robot3.getNext());
                    RobotMessageMap.setRobotMessage(robotId, robot3);
                }
            }
            RobotMessage robot5 = RobotMessageMap.robotMap.get(robotId);
            Route route = new Route(robot5, map);
            TextCoordinate nextPos = route.getNextStep();
            robot5.setNext(nextPos);
            RobotMessageMap.setRobotMessage(robotId, robot5);
        }
        return 0;
    }

    //排队状态时移动
    public void queueLogic() throws IOException {
        Broadcast broadcastInfo = BroadcastMessage.broadcastMessage;
        RobotMessage robot = RobotMessageMap.robotMap.get(robotId);
//        System.out.println(robotId + "自己的是" + robot.getSelfMovingNumber());
//        System.out.println("系统是" + broadcastInfo.getMovingNumber());
        if (broadcastInfo.getMovingNumber() >= robot.getSelfMovingNumber()) {
            RobotMessage robot5 = RobotMessageMap.robotMap.get(robotId);
            long movingNumber = broadcastInfo.getMovingNumber() + 1;
            robot5.setSelfMovingNumber(movingNumber);
            RobotMessageMap.setRobotMessage(robotId, robot5);
            //若到达窗口，改变状态
//            System.out.println("当前坐标" + robot.getPosition());
//            System.out.println("-------------------" + robot.getTermination());
            if (robot.getPosition().equals(robot.getTermination())) {
                long endTime = System.currentTimeMillis();
                RobotMessage robot4 = RobotMessageMap.robotMap.get(robotId);
                //这里改变状态通知药剂师拿药
                Map<String, Object> sendData = new HashMap<>();
                sendData.put("serialNumber", robot4.getSerialNum());
                sendData.put("orderNumber", robot4.getOrder());
                sendData.put("window", robot4.getWindow());
                long deliveryTime = (endTime - robot4.startTime) / 1000;
                sendData.put("deliveryTime", deliveryTime);
                Message deliverOrder = new Message(MessageType.ORDER_SUBMIT, sendData);
                deliverOrder.setSender((InetSocketAddress) RobotsSocketMap.robotsSocketMap.get(robotId).getSocket().getLocalSocketAddress());
                deliverOrder.setReceiver((InetSocketAddress) RobotsSocketMap.robotsSocketMap.get(robotId).getSocket().getRemoteSocketAddress());
                RobotsSocketMap.robotsSocketMap.get(robotId).getOos().writeObject(deliverOrder);
                RobotsSocketMap.robotsSocketMap.get(robotId).getOos().flush();
                System.out.println("改变回家状态成功");
                //改变状态
                if (robot.getRobotStatus() != RobotStatus.MOVING) {
                    Message statusChange = new Message(MessageType.STATUS_EXCHANGE, new ChangeRobot(robot4.getSerialNum(), robot4.getRobotStatus(), RobotStatus.MOVING, robot4.getWindow()));
                    statusChange.setSender((InetSocketAddress) RobotsSocketMap.robotsSocketMap.get(robotId).getSocket().getLocalSocketAddress());
                    statusChange.setReceiver((InetSocketAddress) RobotsSocketMap.robotsSocketMap.get(robotId).getSocket().getRemoteSocketAddress());
                    RobotsSocketMap.robotsSocketMap.get(robotId).getOos().writeObject(statusChange);
                    RobotsSocketMap.robotsSocketMap.get(robotId).getOos().flush();
                    robot4.setRobotStatus(RobotStatus.MOVING);
                }
                //设置回家地址
                robot.setTermination(robot.getBornPosition());
                RobotMessageMap.setRobotMessage(robotId, robot);
                System.out.println("改变回家状态成功");
//            System.out.println("到窗口了"+robot.getTermination());
            } else {//还没到达窗口：执行排队移动逻辑：只有前面是空的时候才走1格
//            System.out.println("之前我的坐标是"+robot.getPosition());
                TextCoordinate nextPos = robot.getPosition();
                TextCoordinate temp = new TextCoordinate(nextPos);
                temp.y--;
                if (broadcastInfo.getMap().getGrid(temp).getGridType().equals(GridType.NULL)) {
                    moveAStep("WEST");
                    if (temp.y > 1) {
                        temp.y--;
                        robot.setNext(temp);
                        RobotMessageMap.setRobotMessage(robotId, robot);
                    }
                }
            }
        }
    }
}